"""
考试管理模块 - 权限控制
"""
from rest_framework import permissions
from django.utils import timezone


class IsExaminationOwnerOrReadOnly(permissions.BasePermission):
    """
    考试所有者或只读权限
    """

    def has_object_permission(self, request, view, obj):
        # 读取权限对所有认证用户开放
        if request.method in permissions.SAFE_METHODS:
            return True

        # 考试创建者和管理员可以修改
        return obj.creator == request.user or request.user.is_admin_user


class CanManageExamination(permissions.BasePermission):
    """
    可以管理考试的权限
    """

    def has_object_permission(self, request, view, obj):
        # 考试所有者和管理员可以管理
        return obj.creator == request.user or request.user.is_admin_user


class IsExaminationSupervisor(permissions.BasePermission):
    """
    考试监考权限
    """

    def has_object_permission(self, request, view, obj):
        return (
            obj.creator == request.user or
            request.user.is_admin_user or
            obj.supervisors.filter(id=request.user.id).exists()
        )


class CanViewExamResults(permissions.BasePermission):
    """
    可以查看考试结果的权限
    """

    def has_object_permission(self, request, view, obj):
        if request.user.is_admin_user:
            return True

        if obj.creator == request.user:
            return True

        if obj.supervisors.filter(id=request.user.id).exists():
            return True

        # 检查是否是考生本人查看自己的成绩
        if hasattr(obj, 'exam_sessions'):
            return obj.exam_sessions.filter(user=request.user).exists()

        return False


class CanParticipateInExam(permissions.BasePermission):
    """
    可以参加考试的权限
    """

    def has_object_permission(self, request, view, obj):
        # 考试必须已发布
        if obj.status != 'published':
            return False

        # 考试必须在进行时间范围内
        now = timezone.now()
        if now < obj.start_time or now > obj.end_time:
            return False

        # 检查是否已经参加过
        if obj.exam_sessions.filter(user=request.user).exists():
            if not obj.allow_retake:
                return False

        return True


class IsSessionOwnerOrSupervisor(permissions.BasePermission):
    """
    会话所有者或监考权限
    """

    def has_object_permission(self, request, view, obj):
        # 会话所有者可以操作
        if obj.user == request.user:
            return True

        # 考试管理员和监考教师可以查看
        examination = obj.examination
        return (
            request.user.is_admin_user or
            examination.creator == request.user or
            examination.supervisors.filter(id=request.user.id).exists()
        )


class CanGradeAnswers(permissions.BasePermission):
    """
    可以评分的权限
    """

    def has_permission(self, request, view):
        """检查是否有评分权限"""
        return request.user.is_teacher or request.user.is_admin_user

    def has_object_permission(self, request, view, obj):
        # 教师和管理员可以评分
        if request.user.is_admin_user:
            return True

        # 检查是否是相关考试的创建者或监考
        examination = obj.exam_session.examination
        return (
            examination.creator == request.user or
            examination.supervisors.filter(id=request.user.id).exists()
        )


class IsAnswerOwnerOrCanGrade(permissions.BasePermission):
    """
    答案所有者或有评分权限
    """

    def has_object_permission(self, request, view, obj):
        # 答案所有者可以查看和修改自己的答案
        if obj.exam_session.user == request.user:
            # 检查考试是否仍在进行中
            session = obj.exam_session
            if session.status == 'in_progress':
                return True

        # 有评分权限的用户可以查看所有答案
        return CanGradeAnswers().has_object_permission(request, view, obj)


class CanManageTemplate(permissions.BasePermission):
    """
    可以管理考试模板的权限
    """

    def has_object_permission(self, request, view, obj):
        # 模板所有者和管理员可以管理
        return obj.creator == request.user or request.user.is_admin_user


class CanAccessQuestionBank(permissions.BasePermission):
    """
    可以访问题库的权限
    """

    def has_object_permission(self, request, view, obj):
        # 管理员可以访问所有题库
        if request.user.is_admin_user:
            return True

        # 题库所有者可以访问
        if obj.owner == request.user:
            return True

        # 公开题库所有人都可以访问
        if obj.is_public:
            return True

        return False


class HasExaminationAccess(permissions.BasePermission):
    """
    具有考试访问权限的综合检查
    """

    def has_permission(self, request, view):
        # 检查用户是否已认证
        if not request.user.is_authenticated:
            return False

        # 对于列表视图，检查基本权限
        if view.action == 'list':
            return True  # 在get_queryset中进行细粒度控制

        # 对于创建操作，需要教师或管理员权限
        if view.action == 'create':
            return request.user.is_teacher or request.user.is_admin_user

        # 参加考试操作需要学生权限
        if view.action == 'join_exam':
            return request.user.is_authenticated

        # 其他操作需要在对象级别检查
        return True

    def has_object_permission(self, request, view, obj):
        # 根据不同操作检查权限
        if view.action in ['retrieve', 'participants', 'statistics']:
            return CanViewExamResults().has_object_permission(request, view, obj)

        elif view.action in ['update', 'partial_update', 'destroy',
                           'publish', 'start', 'end', 'add_questions',
                           'remove_questions', 'reorder_questions']:
            return CanManageExamination().has_object_permission(request, view, obj)

        elif view.action in ['export_results']:
            return CanViewExamResults().has_object_permission(request, view, obj)

        return False


class HasSessionAccess(permissions.BasePermission):
    """
    具有考试会话访问权限的综合检查
    """

    def has_permission(self, request, view):
        # 检查用户是否已认证
        if not request.user.is_authenticated:
            return False

        # 对于列表视图，在get_queryset中进行细粒度控制
        if view.action == 'list':
            return True

        # 参加考试操作
        if view.action == 'join_exam':
            return True

        # 开始考试操作
        if view.action == 'start_exam':
            return True

        # 其他操作需要在对象级别检查
        return True

    def has_object_permission(self, request, view, obj):
        # 根据不同操作检查权限
        if view.action == 'retrieve':
            return IsSessionOwnerOrSupervisor().has_object_permission(request, view, obj)

        elif view.action in ['submit_answer', 'submit_exam', 'get_remaining_time']:
            # 只有会话所有者可以进行考试操作
            return obj.user == request.user

        return False


class HasAnswerAccess(permissions.BasePermission):
    """
    具有答案访问权限的综合检查
    """

    def has_permission(self, request, view):
        # 检查用户是否已认证
        if not request.user.is_authenticated:
            return False

        # 对于列表视图，在get_queryset中进行细粒度控制
        if view.action == 'list':
            return True

        # 批量评分需要教师权限
        if view.action == 'batch_grade':
            return request.user.is_teacher or request.user.is_admin_user

        return True

    def has_object_permission(self, request, view, obj):
        # 根据不同操作检查权限
        if view.action == 'retrieve':
            return IsAnswerOwnerOrCanGrade().has_object_permission(request, view, obj)

        elif view.action in ['update', 'partial_update']:
            # 只有考生可以在考试进行中修改答案
            if obj.exam_session.user == request.user:
                session = obj.exam_session
                return session.status == 'in_progress'
            return False

        return False


class IsTemplateOwnerOrReadOnly(permissions.BasePermission):
    """
    模板所有者或只读权限
    """

    def has_object_permission(self, request, view, obj):
        # 读取权限对所有认证用户开放
        if request.method in permissions.SAFE_METHODS:
            return True

        # 模板创建者和管理员可以修改
        return obj.creator == request.user or request.user.is_admin_user


class HasTemplateAccess(permissions.BasePermission):
    """
    具有模板访问权限的综合检查
    """

    def has_permission(self, request, view):
        # 检查用户是否已认证
        if not request.user.is_authenticated:
            return False

        # 创建模板需要教师权限
        if view.action == 'create':
            return request.user.is_teacher or request.user.is_admin_user

        # 其他操作在对象级别检查
        return True

    def has_object_permission(self, request, view, obj):
        # 根据不同操作检查权限
        if view.action in ['retrieve']:
            return IsTemplateOwnerOrReadOnly().has_object_permission(request, view, obj)

        elif view.action in ['update', 'partial_update', 'destroy']:
            return CanManageTemplate().has_object_permission(request, view, obj)

        elif view.action == 'create_exam_from_template':
            # 只有模板所有者或管理员可以使用模板
            return obj.creator == request.user or request.user.is_admin_user

        return False


class HasQuestionBankAccessForExam(permissions.BasePermission):
    """
    具有考试用题库访问权限
    """

    def has_permission(self, request, view):
        # 检查用户是否已认证
        if not request.user.is_authenticated:
            return False

        # 只有教师和管理员可以选择题库
        return request.user.is_teacher or request.user.is_admin_user

    def has_object_permission(self, request, view, obj):
        return CanAccessQuestionBank().has_object_permission(request, view, obj)


class IsExamInProgress(permissions.BasePermission):
    """
    检查考试是否在进行中
    """

    def has_object_permission(self, request, view, obj):
        # 考试必须在进行中
        return obj.status == 'ongoing'


class IsExamPublished(permissions.BasePermission):
    """
    检查考试是否已发布
    """

    def has_object_permission(self, request, view, obj):
        # 考试必须已发布
        return obj.status == 'published'


class IsExamDraft(permissions.BasePermission):
    """
    检查考试是否为草稿状态
    """

    def has_object_permission(self, request, view, obj):
        # 考试必须为草稿状态才能修改
        return obj.status == 'draft'


class CanSubmitExam(permissions.BasePermission):
    """
    检查是否可以提交考试
    """

    def has_object_permission(self, request, view, obj):
        # 检查考试会话状态
        if obj.status != 'in_progress':
            return False

        # 检查考试是否还在进行时间范围内
        examination = obj.examination
        now = timezone.now()

        if now > examination.end_time:
            return False

        return True


class CheatDetectionPermission(permissions.BasePermission):
    """
    作弊检测权限
    """

    def has_permission(self, request, view):
        # 只有管理员和监考教师可以进行作弊检测
        return request.user.is_admin_user or request.user.is_teacher

    def has_object_permission(self, request, view, obj):
        examination = obj.examination if hasattr(obj, 'examination') else obj

        return (
            request.user.is_admin_user or
            examination.creator == request.user or
            examination.supervisors.filter(id=request.user.id).exists()
        )